﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="IncompatibleMatrixMatrixException.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Exceptions
{
    #region Usings

    using System;
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.Security;

    using ExulLibrary.Mathematics.LinearAlgebra.Properties;

    #endregion

    /// <summary>
    ///     Describes an error when the second matrix is incompatible with the first matrix for some operation.
    /// </summary>
    [Serializable]
    public sealed class IncompatibleMatrixMatrixException : ArgumentException
    {
        #region Constructors and Destructors

        #region public

        /// <summary>
        ///     Initializes a new instance of the <see cref="IncompatibleMatrixMatrixException"/> class.
        /// </summary>
        /// <param name="firstMatrixParamName">
        ///     The name of the first matrix parameter.
        /// </param>
        /// <param name="firstMatrixRowsCount">
        ///     The rows count of the first matrix.
        /// </param>
        /// <param name="firstMatrixColumnsCount">
        ///     The columns count of the first matrix.
        /// </param>
        /// <param name="secondMatrixParamName">
        ///     The name of the second matrix parameter.
        /// </param>
        /// <param name="secondMatrixRowsCount">
        ///     The rows count of the second matrix.
        /// </param>
        /// <param name="secondMatrixColumnsCount">
        ///     The columns count of the second matrix.
        /// </param>
        /// <param name="secondMatrixExpectedRowsCount">
        ///     The expected rows count of the second matrix.
        /// </param>
        /// <param name="secondMatrixExpectedColumnsCount">
        ///     The expected columns count of the second matrix.
        /// </param>
        public IncompatibleMatrixMatrixException(
            string firstMatrixParamName,
            int firstMatrixRowsCount,
            int firstMatrixColumnsCount,
            string secondMatrixParamName,
            int secondMatrixRowsCount,
            int secondMatrixColumnsCount,
            int secondMatrixExpectedRowsCount,
            int secondMatrixExpectedColumnsCount)
            : this(
                firstMatrixParamName,
                firstMatrixRowsCount,
                firstMatrixColumnsCount,
                secondMatrixParamName,
                secondMatrixRowsCount,
                secondMatrixColumnsCount,
                secondMatrixExpectedRowsCount,
                secondMatrixExpectedColumnsCount,
                null)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="IncompatibleMatrixMatrixException"/> class.
        /// </summary>
        /// <param name="firstMatrixParamName">
        ///     The name of the first matrix parameter.
        /// </param>
        /// <param name="firstMatrixRowsCount">
        ///     The rows count of the first matrix.
        /// </param>
        /// <param name="firstMatrixColumnsCount">
        ///     The columns count of the first matrix.
        /// </param>
        /// <param name="secondMatrixParamName">
        ///     The name of the second matrix parameter.
        /// </param>
        /// <param name="secondMatrixRowsCount">
        ///     The rows count of the second matrix.
        /// </param>
        /// <param name="secondMatrixColumnsCount">
        ///     The columns count of the second matrix.
        /// </param>
        /// <param name="secondMatrixExpectedRowsCount">
        ///     The expected rows count of the second matrix.
        /// </param>
        /// <param name="secondMatrixExpectedColumnsCount">
        ///     The expected columns count of the second matrix.
        /// </param>
        /// <param name="innerException">
        ///     The inner exception.
        /// </param>
        public IncompatibleMatrixMatrixException(
            string firstMatrixParamName,
            int firstMatrixRowsCount,
            int firstMatrixColumnsCount,
            string secondMatrixParamName,
            int secondMatrixRowsCount,
            int secondMatrixColumnsCount,
            int secondMatrixExpectedRowsCount,
            int secondMatrixExpectedColumnsCount,
            Exception innerException)
            : base(Resources.MatrixMatrixAreIncompatible, secondMatrixParamName, innerException)
        {
            this.FirstMatrixParamName = firstMatrixParamName;
            this.SecondMatrixParamName = secondMatrixParamName;
            this.FirstMatrixRowsCount = firstMatrixRowsCount;
            this.FirstMatrixColumnsCount = firstMatrixColumnsCount;
            this.SecondMatrixRowsCount = secondMatrixRowsCount;
            this.SecondMatrixColumnsCount = secondMatrixColumnsCount;
            this.SecondMatrixExpectedRowsCount = secondMatrixExpectedRowsCount;
            this.SecondMatrixExpectedColumnsCount = secondMatrixExpectedColumnsCount;
        }

        #endregion

        #region private

        /// <summary>
        ///     Initializes a new instance of the <see cref="IncompatibleMatrixMatrixException"/> class.
        /// </summary>
        /// <param name="info">
        ///     The object that holds the serialized object data.
        /// </param>
        /// <param name="context">
        ///     The contextual information about the source or destination.
        /// </param>
        private IncompatibleMatrixMatrixException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            this.FirstMatrixParamName = info.GetString("FirstMatrixParamName");
            this.SecondMatrixParamName = info.GetString("SecondMatrixParamName");
            this.FirstMatrixRowsCount = info.GetInt32("FirstMatrixRowsCount");
            this.FirstMatrixColumnsCount = info.GetInt32("FirstMatrixColumnsCount");
            this.SecondMatrixRowsCount = info.GetInt32("SecondMatrixRowsCount");
            this.SecondMatrixColumnsCount = info.GetInt32("SecondMatrixColumnsCount");
            this.SecondMatrixExpectedRowsCount = info.GetInt32("SecondMatrixExpectedRowsCount");
            this.SecondMatrixExpectedColumnsCount = info.GetInt32("SecondMatrixExpectedColumnsCount");
        }

        #endregion

        #endregion

        #region Properties

        #region public

        /// <summary>
        ///     Gets the columns count of the first matrix.
        /// </summary>
        /// <value>
        ///     The columns count of the first matrix.
        /// </value>
        public int FirstMatrixColumnsCount
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the name of the first matrix parameter.
        /// </summary>
        /// <value>
        ///     The name of the first matrix parameter.
        /// </value>
        public string FirstMatrixParamName
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the rows count of the first matrix.
        /// </summary>
        /// <value>
        ///     The rows count of the first matrix.
        /// </value>
        public int FirstMatrixRowsCount
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the columns count of the second matrix.
        /// </summary>
        /// <value>
        ///     The columns count of the second matrix.
        /// </value>
        public int SecondMatrixColumnsCount
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the expected columns count of the second matrix.
        /// </summary>
        /// <value>
        ///     The expected columns count of the second matrix.
        /// </value>
        public int SecondMatrixExpectedColumnsCount
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the expected rows count of the second matrix.
        /// </summary>
        /// <value>
        ///     The expected rows count of the second matrix.
        /// </value>
        public int SecondMatrixExpectedRowsCount
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the name of the second matrix parameter.
        /// </summary>
        /// <value>
        ///     The name of the second matrix parameter.
        /// </value>
        public string SecondMatrixParamName
        {
            get;
            private set;
        }

        /// <summary>
        ///     Gets the rows count of the second matrix.
        /// </summary>
        /// <value>
        ///     The rows count of the second matrix.
        /// </value>
        public int SecondMatrixRowsCount
        {
            get;
            private set;
        }

        #endregion

        #endregion

        #region Overridden Properties

        #region public

        /// <summary>
        ///     Gets the error message and the parameter name, or only the error message if no parameter name is set.
        /// </summary>
        /// <value>
        ///     A text string describing the details of the exception.
        /// </value>
        public override string Message
        {
            get
            {
                return string.Format(
                    CultureInfo.CurrentCulture,
                    base.Message,
                    this.FirstMatrixParamName,
                    this.SecondMatrixParamName,
                    this.FirstMatrixRowsCount,
                    this.FirstMatrixColumnsCount,
                    this.SecondMatrixRowsCount,
                    this.SecondMatrixColumnsCount,
                    this.SecondMatrixExpectedRowsCount,
                    this.SecondMatrixExpectedColumnsCount);
            }
        }

        #endregion

        #endregion

        #region Overridden Methods

        #region public

        /// <summary>
        ///     Sets the <see cref="SerializationInfo"/> object with the parameter name and additional exception information.
        /// </summary>
        /// <param name="info">
        ///     The object that holds the serialized object data.
        /// </param>
        /// <param name="context">
        ///     The contextual information about the source or destination.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="info"/> is <see langword="null"/>.
        /// </exception>
        [SecurityCritical]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);

            info.AddValue("FirstMatrixParamName", this.FirstMatrixParamName);
            info.AddValue("SecondMatrixParamName", this.SecondMatrixParamName);
            info.AddValue("FirstMatrixRowsCount", this.FirstMatrixRowsCount);
            info.AddValue("FirstMatrixColumnsCount", this.FirstMatrixColumnsCount);
            info.AddValue("SecondMatrixRowsCount", this.SecondMatrixRowsCount);
            info.AddValue("SecondMatrixColumnsCount", this.SecondMatrixColumnsCount);
            info.AddValue("SecondMatrixExpectedRowsCount", this.SecondMatrixExpectedRowsCount);
            info.AddValue("SecondMatrixExpectedColumnsCount", this.SecondMatrixExpectedColumnsCount);
        }

        #endregion

        #endregion
    }
}